import { native, NodePredicate, QvogHint } from 'qvog-dsl';
import { Constant, InvokeExpr, Value, Variable } from 'qvog-types';
import { P, Q } from '~/core/dsl';

const ContainsInvokeExpr: NodePredicate<Value> = {
    is(node: Value): node is Value {
        return node.stream().any(Q(InvokeExpr));
    },
};

const SensitiveItems = ['password', 'pwd'];

export default native<QvogHint>({ name: '@security/dsl/sensitive-localstorage' })()
    .match(ContainsInvokeExpr)
    .when((node) => {
        return node.stream().any(
            Q(
                InvokeExpr,
                P<InvokeExpr>((v) => v.target === 'setItem')
                    .and<Variable>(
                        (v) => v.name === 'localStorage',
                        (v) => v.base! as Variable,
                        Variable
                    )
                    .and((v) => v.argCount === 2)
                    .and<Constant>(
                        (v) => SensitiveItems.includes(v.stringValue),
                        (s) => s.args[0] as Constant,
                        Constant
                    )
                    .done()
            )
        );
    })
    .report({ message: '`localStorage` is used to store sensitive information' });
